﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Text.RegularExpressions;
using System.Xml;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using NetworkUtils;



namespace Server
{
    class RemoteClient
    {
        private TcpClient client;
        private NetworkStream streamToClient;
        private const int BufferSize = 1024 * 8;
        private byte[] buffer;
        private string msg = "";
        public delegate void MsgDelegate(object msg);
        public event MsgDelegate OnInfoReceived;
        public event MsgDelegate OnDataReceived;

        public RemoteClient(TcpClient client)
        {
            this.client = client;
            Console.WriteLine("Client Connected {0} <---{1}", client.Client.LocalEndPoint, client.Client.RemoteEndPoint);
            streamToClient = client.GetStream();
            buffer = new byte[BufferSize];
            //AsyncCallback callback = new AsyncCallback(ReadComplete);
            Read();
            //streamToClient.BeginRead(buffer, 0, BufferSize, callback, null);
        }

        private async void Read()
        {
            int bytesRead = 0;
            
            try
            {                       
                while (!ProtocolHelper.IsMacth(msg))
                {
                    bytesRead = await streamToClient.ReadAsync(buffer, 0, BufferSize);
                    if (bytesRead == 0) throw new Exception("read 返回0");
                    msg += Encoding.Unicode.GetString(buffer, 0, bytesRead);
                    Array.Clear(buffer, 0, buffer.Length); //清空缓存
                }
                string ptcStr = ProtocolHelper.GetProtocolStr(msg);
                ProtocolObj ptc = ProtocolHelper.GetProtocolObj(ptcStr);
                msg = msg.Substring(ptcStr.Length); //把协议头截掉
                while (msg.Length < ptc.len) //如果消息长度不满足数据长度
                {
                    bytesRead = await streamToClient.ReadAsync(buffer, 0, BufferSize);
                    if (bytesRead == 0) throw new Exception("read 返回0");
                    msg += Encoding.Unicode.GetString(buffer, 0, bytesRead);
                    Array.Clear(buffer, 0, buffer.Length); //清空缓存
                }
                string data = msg.Substring(0, ptc.len);
                Console.WriteLine("接收到的序列字符：" + data);
                MsgProcess(data, ptc);
                msg = msg.Substring(ptc.len);
                Read(); // 递归调用
            }
            catch(Exception e)
            {
                if (streamToClient != null)
                {
                    streamToClient.Dispose();
                }
                client.Close();
                Console.WriteLine(e.Message);
            }
        }

        public void MsgProcess(string msg, ProtocolObj ptc) //根据协议头,解析消息,并异步处理
        {
            switch (ptc.type)
            {
                case MsgType.Info:
                    Console.WriteLine("收到Info信息");
                    new Task(()=>InfoProcess(msg)).Start();
                    break;
                case MsgType.Data:
                    Console.WriteLine("收到Data信息");
                    DataProcess(msg);
                    //new Task(() => DataProcess(msg)).Start();
                    break;
                case MsgType.Beat:
                    Console.WriteLine("收到心跳");
                    break;
            }
        }

        public void InfoProcess(string msg)
        {
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(msg));
            ms.Position = 0;
            BinaryFormatter formatter = new BinaryFormatter();
            Info info = (Info)formatter.Deserialize(ms);
            ms.Close();
            OnInfoReceived(info);
        }

        public void DataProcess(string msg)
        {
            MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(msg));
            ms.Position = 0;
            BinaryFormatter formatter = new BinaryFormatter();
            Data data = (Data)formatter.Deserialize(ms);
            ms.Close();
            OnDataReceived(data);
        }
    }

    public enum MsgType
    {
        Info = 0,
        Beat = 1, //心跳包
        Data = 2
    };


    public class ProtocolObj
    {
        public int len { get; set; }
        public MsgType type { get; set; }
        public ProtocolObj(int len, MsgType type)
        {
            this.len = len;
            this.type = type;
        }
    }

    static class ProtocolHelper
    {
        const string pattern = "(^<protocol>.*?</protocol>)";

        static public ProtocolObj GetProtocolObj(string ptcStr)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(ptcStr);
            var root = doc.DocumentElement.SelectSingleNode("MSG");
            int len = int.Parse(root.Attributes["len"].Value);
            MsgType type = (MsgType)int.Parse(root.Attributes["type"].Value);
            return new ProtocolObj(len, type);
        }
            

        static public string GetProtocolStr(string msg)
        {
            if (Regex.IsMatch(msg, pattern))
            {
                // 获取匹配的值
                string match = Regex.Match(msg, pattern).Groups[0].Value;
                return match;
            }
            throw new Exception("msg not match patter");
        }

        public static bool IsMacth(string msg)
        {
            return Regex.IsMatch(msg, pattern);
        }

        public static string ToString(ProtocolObj ptcObj)
        {
            string type = ptcObj.type.ToString();
            string len = ptcObj.len.ToString();
            string ptc = "<protocol><MSG type="+type+" len="+len+"/></protocol>";
            return ptc;
        }
    }

}
